package com.example.clock_demo.service.impl;

import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.read.listener.PageReadListener;
import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.clock_demo.dto.ShiftImportDTO;
import com.example.clock_demo.entitys.Shift;
import com.example.clock_demo.mapper.ShiftMapper;
import com.example.clock_demo.service.ShiftService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.math.BigDecimal;

import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 班次信息服务实现类
 */
@Service
public class ShiftServiceImpl extends ServiceImpl<ShiftMapper, Shift> implements ShiftService {



    @Override
    @Transactional
    public void importShifts(InputStream inputStream) {
        EasyExcel.read(inputStream, ShiftImportDTO.class, new PageReadListener<ShiftImportDTO>(dataList -> {
            List<String> shiftCodesFromExcel = dataList.stream()
                    .map(ShiftImportDTO::getShiftCode)
                    .filter(StrUtil::isNotBlank)
                    .collect(Collectors.toList());
            if (shiftCodesFromExcel.isEmpty()) {
                return;
            }

            Map<String, Shift> existingShiftsMap = this.list(new QueryWrapper<Shift>().in("shift_code", shiftCodesFromExcel))
                    .stream()
                    .collect(Collectors.toMap(Shift::getShiftCode, shift -> shift));
            List<Shift> shiftsToUpdate = new ArrayList<>();
            List<Shift> shiftsToInsert = new ArrayList<>();

            for (ShiftImportDTO dto : dataList) {
                if (StrUtil.isBlank(dto.getShiftCode())) {
                    continue;
                }

                Shift existingShift = existingShiftsMap.get(dto.getShiftCode());

                if (existingShift != null) {
                    // 添加日志，比较更新前后的值
                    System.out.println("更新前 - " + existingShift.getShiftCode() + ": " + 
                        existingShift.getStartTime() + " -> " + existingShift.getEndTime());
                    updateShiftFromDTO(existingShift, dto);
                    System.out.println("更新后 - " + existingShift.getShiftCode() + ": " + 
                        existingShift.getStartTime() + " -> " + existingShift.getEndTime());
                    shiftsToUpdate.add(existingShift);
                } else {
                    Shift newShift = createShiftFromDTO(dto);
                    if (newShift != null) {
                        shiftsToInsert.add(newShift);
                    }
                }
            }

            if (!shiftsToUpdate.isEmpty()) {
                this.updateBatchById(shiftsToUpdate);
            }
            if (!shiftsToInsert.isEmpty()) {
                this.saveBatch(shiftsToInsert);
            }
        })).sheet().doRead();
    }

    /**
     * 从DTO更新现有班次信息
     */
    private void updateShiftFromDTO(Shift existingShift, ShiftImportDTO dto) {
        existingShift.setShiftName(dto.getShiftName());

        LocalTime startTime = null;
        LocalTime endTime = null;

        // 处理开始时间
        if (StringUtils.isNotBlank(dto.getStartTime())) {
            try {
                startTime = parseFlexibleTime(dto.getStartTime());
                existingShift.setStartTime(startTime);
            } catch (IllegalArgumentException e) {
                // 时间解析失败，保持原来的时间
            }
        }

        // 处理结束时间
        if (StringUtils.isNotBlank(dto.getEndTime())) {
            try {
                endTime = parseFlexibleTime(dto.getEndTime());
                existingShift.setEndTime(endTime);
            } catch (IllegalArgumentException e) {
                // 时间解析失败，保持原来的时间
            }
        }

        existingShift.setEarlyPunchInMinutes(dto.getEarlyPunchInMinutes());
        existingShift.setLatePunchOutMinutes(dto.getLatePunchOutMinutes());

        // 计算并设置班次时长
        if (existingShift.getStartTime() != null && existingShift.getEndTime() != null) {
            BigDecimal duration = calculateShiftDuration(existingShift.getStartTime(), existingShift.getEndTime());
            existingShift.setShiftDurationHours(duration);
        }
    }

    /**
     * 从DTO创建新的班次信息
     */
    private Shift createShiftFromDTO(ShiftImportDTO dto) {
        Shift newShift = new Shift();
        newShift.setShiftCode(dto.getShiftCode());
        newShift.setShiftName(dto.getShiftName());

        LocalTime startTime = null;
        LocalTime endTime = null;

        // 处理开始时间
        if (StringUtils.isNotBlank(dto.getStartTime())) {
            try {
                startTime = parseFlexibleTime(dto.getStartTime());
                newShift.setStartTime(startTime);
            } catch (IllegalArgumentException e) {
                // 时间解析失败，记录日志并跳过该记录
                return null;
            }
        }

        // 处理结束时间
        if (StringUtils.isNotBlank(dto.getEndTime())) {
            try {
                endTime = parseFlexibleTime(dto.getEndTime());
                newShift.setEndTime(endTime);
            } catch (IllegalArgumentException e) {
                // 时间解析失败，记录日志并跳过该记录
                return null;
            }
        }

        newShift.setEarlyPunchInMinutes(dto.getEarlyPunchInMinutes());
        newShift.setLatePunchOutMinutes(dto.getLatePunchOutMinutes());

        // 计算并设置班次时长
        if (startTime != null && endTime != null) {
            BigDecimal duration = calculateShiftDuration(startTime, endTime);
            newShift.setShiftDurationHours(duration);
        }

        return newShift;
    }

    /**
     * 计算班次时长（小时），处理跨天班次
     */
    private BigDecimal calculateShiftDuration(LocalTime startTime, LocalTime endTime) {
        if (startTime == null || endTime == null) {
            return BigDecimal.ZERO;
        }

        long minutes;

        // 判断是否跨天
        if (endTime.isBefore(startTime) || endTime.equals(startTime)) {
            // 跨天班次：结束时间小于等于开始时间
            // 计算到午夜的时间 + 从午夜到结束时间
            long minutesToMidnight = Duration.between(startTime, LocalTime.MAX).toMinutes() + 1;
            long minutesFromMidnight = Duration.between(LocalTime.MIN, endTime).toMinutes();
            minutes = minutesToMidnight + minutesFromMidnight;
        } else {
            // 同天班次
            minutes = Duration.between(startTime, endTime).toMinutes();
        }

        // 转换为小时，保留2位小数
        BigDecimal hours = new BigDecimal(minutes).divide(new BigDecimal("60"), 2, RoundingMode.HALF_UP);
        return hours;
    }

    // 辅助方法：解析灵活的时间格式
    private LocalTime parseFlexibleTime(String timeStr) {
        if (timeStr == null || timeStr.trim().isEmpty()) {
            throw new IllegalArgumentException("时间字符串不能为空");
        }

        timeStr = timeStr.trim();

        // 尝试多种可能的格式
        DateTimeFormatter formatter = new DateTimeFormatterBuilder()
                .appendOptional(DateTimeFormatter.ofPattern("H:mm"))   // 24小时制，不带前导零
                .appendOptional(DateTimeFormatter.ofPattern("HH:mm"))  // 24小时制，带前导零
                .appendOptional(DateTimeFormatter.ofPattern("h:mm a"))  // 12小时制，带AM/PM
                .toFormatter()
                .withLocale(Locale.US);

        try {
            return LocalTime.parse(timeStr, formatter);
        } catch (DateTimeParseException e) {
            throw new IllegalArgumentException("无效的时间格式: " + timeStr +
                    "。请使用HH:mm或H:mm或h:mm AM/PM格式", e);
        }
    }

    @Override
    public IPage<Shift> findPage(Long current, Long size, String name) {
        IPage<Shift> page = new Page<>(current, size);
        QueryWrapper<Shift> queryWrapper = new QueryWrapper<>();
        if (StrUtil.isNotBlank(name)) {
            queryWrapper.like("shift_name", name);
        }
        queryWrapper.orderByAsc("id");
        return this.page(page, queryWrapper);
    }

    @Override
    public Shift getShiftByCode(String shiftCode) {
        if (StrUtil.isBlank(shiftCode)) {
            return null;
        }
        QueryWrapper<Shift> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("shift_code", shiftCode);
        return this.getOne(queryWrapper);
    }
}
